using System;
using System.Collections.Generic;
using System.Threading;

namespace NExt.Handler.Base.Common.Cache
{
    public class ConcurrentCache<TCache, TKey, TValue> where TCache : ConcurrentCache<TCache, TKey, TValue>
    {
        private static readonly ReaderWriterLockSlim Locker;
        private static readonly IDictionary<TKey, TValue> Dictionary;

        static ConcurrentCache()
        {
            Locker = new ReaderWriterLockSlim();
            Dictionary = new Dictionary<TKey, TValue>();
        }

        protected static TValue GetOrAdd(TKey key, Func<TValue> valueBuilder)
        {
            TValue value;
            Locker.EnterReadLock();
            try
            {
                if (Dictionary.TryGetValue(key, out value))
                {
                    return value;
                }
            }
            finally
            {
                Locker.ExitReadLock();
            }

            Locker.EnterWriteLock();
            try
            {
                if (Dictionary.TryGetValue(key, out value))
                {
                    return value;
                }

                value = valueBuilder();
                Dictionary.Add(key, value);
                return value;
            }
            finally
            {
                Locker.ExitWriteLock();
            }
        }
    }
}